/*
 * Copyright 2016 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#ifndef GrShaderVar_DEFINED
#define GrShaderVar_DEFINED

#include "include/core/SkString.h"
#include "include/private/gpu/ganesh/GrTypesPriv.h"
#include "src/core/SkSLTypeShared.h"

struct GrShaderCaps;

/* *
 * Represents a variable in a shader
 */
class GrShaderVar {
public:
    enum class TypeModifier {
        None,
        Out,
        In,
        InOut,
        Uniform,
    };

    /* * Values for array count that have special meaning. We allow 1-sized arrays. */
    enum {
        kNonArray = 0, // not an array
    };

    /* * Defaults to a void with no type modifier or layout qualifier. */
    GrShaderVar() : fType(SkSLType::kVoid), fTypeModifier(TypeModifier::None), fCount(kNonArray) {}

    GrShaderVar(SkString name, SkSLType type, int arrayCount = kNonArray)
        : fType(type), fTypeModifier(TypeModifier::None), fCount(arrayCount), fName(std::move(name))
    {}
    GrShaderVar(const char *name, SkSLType type, int arrayCount = kNonArray)
        : GrShaderVar(SkString(name), type, arrayCount)
    {}

    GrShaderVar(SkString name, SkSLType type, TypeModifier typeModifier)
        : fType(type), fTypeModifier(typeModifier), fCount(kNonArray), fName(std::move(name))
    {}
    GrShaderVar(const char *name, SkSLType type, TypeModifier typeModifier)
        : GrShaderVar(SkString(name), type, typeModifier)
    {}

    GrShaderVar(SkString name, SkSLType type, TypeModifier typeModifier, int arrayCount)
        : fType(type), fTypeModifier(typeModifier), fCount(arrayCount), fName(std::move(name))
    {}

    GrShaderVar(SkString name, SkSLType type, TypeModifier typeModifier, int arrayCount, SkString layoutQualifier,
        SkString extraModifier)
        : fType(type),
          fTypeModifier(typeModifier),
          fCount(arrayCount),
          fName(std::move(name)),
          fLayoutQualifier(std::move(layoutQualifier)),
          fExtraModifiers(std::move(extraModifier))
    {}

    GrShaderVar(const GrShaderVar &) = default;
    GrShaderVar &operator = (const GrShaderVar &) = default;
    GrShaderVar(GrShaderVar &&) = default;
    GrShaderVar &operator = (GrShaderVar &&) = default;

    /* * Sets as a non-array. */
    void set(SkSLType type, const char *name)
    {
        SkASSERT(SkSLType::kVoid != type);
        fType = type;
        fName = name;
    }

    /* * Is the var an array. */
    bool isArray() const
    {
        return kNonArray != fCount;
    }

    /* * Get the array length. */
    int getArrayCount() const
    {
        return fCount;
    }

    /* * Get the name. */
    const SkString &getName() const
    {
        return fName;
    }

    /* * Shortcut for this->getName().c_str(); */
    const char *c_str() const
    {
        return this->getName().c_str();
    }

    /* * Get the type. */
    SkSLType getType() const
    {
        return fType;
    }

    TypeModifier getTypeModifier() const
    {
        return fTypeModifier;
    }
    void setTypeModifier(TypeModifier type)
    {
        fTypeModifier = type;
    }

    /* * Appends to the layout qualifier. */
    void addLayoutQualifier(const char *layoutQualifier)
    {
        if (!layoutQualifier || !strlen(layoutQualifier)) {
            return;
        }
        if (fLayoutQualifier.isEmpty()) {
            fLayoutQualifier = layoutQualifier;
        } else {
            fLayoutQualifier.appendf(", %s", layoutQualifier);
        }
    }

    /* * Appends to the modifiers. */
    void addModifier(const char *modifier)
    {
        if (!modifier || !strlen(modifier)) {
            return;
        }
        if (fExtraModifiers.isEmpty()) {
            fExtraModifiers = modifier;
        } else {
            fExtraModifiers.appendf(" %s", modifier);
        }
    }

    /* * Write a declaration of this variable to out. */
    void appendDecl(const GrShaderCaps *, SkString *out) const;

private:
    SkSLType fType;
    TypeModifier fTypeModifier;
    int fCount;

    SkString fName;
    SkString fLayoutQualifier;
    SkString fExtraModifiers;
};

#endif
